#include "mainwindow.h"
#include "material.h"
#include "sqlhelper.h"
#include "settings.h"

#include <QDebug>
#include <QDateTime>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QInputDialog>

#include <QChartView>
#include <QBarSeries>
#include <QBarSet>
#include <QBarCategoryAxis>
#include <QValueAxis>

#include "xlsxdocument.h"
#include "xlsxchartsheet.h"
#include "xlsxcellrange.h"
#include "xlsxchart.h"
#include "xlsxrichstring.h"
#include "xlsxworkbook.h"

namespace MISystem
{

    MainWindow::MainWindow(QWidget* parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindowClass)
    {
        ui->setupUi(this);

        setupTab1();
        setupTab2();
        setupTab3();
        setupTab4();
    }

    void MainWindow::setupTab1()
    {
        ui->stopButton->setEnabled(false);

        _cap.open(0);
        if (!_cap.isOpened())
        {
            ui->resultTextEdit->setPlainText("无法打开摄像头！");
            ui->startButton->setEnabled(false);
            return;
        }

        _timer = new QTimer(this);
        connect(_timer, &QTimer::timeout, this, &MainWindow::processFrame);
    }

    void MainWindow::setupTab2()
    {
        ui->stockTable->setSelectionBehavior(QAbstractItemView::SelectRows);
        ui->stockTable->setSelectionMode(QAbstractItemView::SingleSelection);
        ui->stockTable->setAlternatingRowColors(true);
        ui->stockTable->horizontalHeader()->setStretchLastSection(true);
        ui->stockTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->stockTable->setSortingEnabled(true);

        ui->stockTable->setColumnCount(5);
        ui->stockTable->setHorizontalHeaderLabels(
            QStringList() << "材料 ID" << "材料名称" << "库存数量" << "存放位置" << "创建时间");
        ui->stockTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

        refreshStockTable();
    }

    void MainWindow::setupTab3()
    {
        ui->operationTable->setSelectionBehavior(QAbstractItemView::SelectRows);
        ui->operationTable->setSelectionMode(QAbstractItemView::SingleSelection);
        ui->operationTable->setAlternatingRowColors(true);
        ui->operationTable->horizontalHeader()->setStretchLastSection(true);
        ui->operationTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
        ui->operationTable->setSortingEnabled(true);

        ui->operationTable->setColumnCount(6);
        ui->operationTable->setHorizontalHeaderLabels(
            QStringList() << "操作 ID" << "材料 ID" << "操作类型" << "出入库数量" << "操作人" << "操作时间");
        ui->operationTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
        ui->operationTable->verticalHeader()->setVisible(false);

        refreshOperationTable();
        updateStockBarChart();
    }

    void MainWindow::setupTab4()
    {
        SettingsManager::instance().loadSettings();

        ui->lackRemindInput->setText(QString::number(SettingsManager::instance().lackRemindThreshold()));
        ui->stockWarningInput->setText(QString::number(SettingsManager::instance().stockWarningThreshold()));
        ui->systemStatusInput->setText(SettingsManager::instance().systemStatus());
        ui->operatorNameInput->setText(SettingsManager::instance().operatorName());

        connect(ui->lackRemindInput, &QLineEdit::editingFinished, [this]() {
            SettingsManager::instance().setLackRemindThreshold(ui->lackRemindInput->text().toInt());
            SettingsManager::instance().saveSettings();
            });
        connect(ui->stockWarningInput, &QLineEdit::editingFinished, [this]() {
            SettingsManager::instance().setStockWarningThreshold(ui->stockWarningInput->text().toInt());
            SettingsManager::instance().saveSettings();
            });
        connect(ui->systemStatusInput, &QLineEdit::editingFinished, [this]() {
            SettingsManager::instance().setSystemStatus(ui->systemStatusInput->text());
            SettingsManager::instance().saveSettings();
            });
        connect(ui->operatorNameInput, &QLineEdit::editingFinished, [this]() {
            SettingsManager::instance().setOperatorName(ui->operatorNameInput->text());
            SettingsManager::instance().saveSettings();
            });
    }

    MainWindow::~MainWindow()
    {
        if (_cap.isOpened())
            _cap.release();

        delete ui;
    }

    void MainWindow::on_startButton_clicked()
    {
        if (!_cap.isOpened()) return;

        _timer->start(30);

        ui->startButton->setEnabled(false);
        ui->stopButton->setEnabled(true);
    }

    void MainWindow::on_stopButton_clicked()
    {
        _timer->stop();

        ui->startButton->setEnabled(true);
        ui->stopButton->setEnabled(false);

        ui->resultLabel->clear();
        ui->resultTextEdit->clear();
    }

    void MainWindow::on_refreshStockButton_clicked()
    {
        refreshStockTable();
        updateStockBarChart();
    }

    void MainWindow::on_refreshOperationButton_clicked()
    {
        refreshOperationTable();
        updateStockBarChart();
    }

    void MainWindow::processFrame()
    {
        cv::Mat frame;
        if (!_cap.read(frame)) {
            return;
        }

        QImage qimg = cvMatToQImage(frame);
        ui->viewLabel->setPixmap(QPixmap::fromImage(qimg).scaled(
            ui->viewLabel->size(), Qt::KeepAspectRatio, Qt::FastTransformation));

        std::vector<cv::Point> points;
        cv::Mat frameGray;
        cv::cvtColor(frame, frameGray, cv::COLOR_BGR2GRAY);

        QString decodedText = QString::fromStdString(
            _qrDecoder.detectAndDecode(frameGray, points));

        if (!decodedText.isEmpty() && points.size() > 0)
        {
            cv::polylines(frame, points, true, cv::Scalar(0, 255, 0), 3);

            QImage resultImg = cvMatToQImage(frame);
            ui->resultLabel->setPixmap(QPixmap::fromImage(resultImg).scaled(
                ui->resultLabel->size(), Qt::KeepAspectRatio, Qt::FastTransformation));

            QString time = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
            ui->resultTextEdit->setPlainText(
                QString("检测时间：%1\n---------------\n解码内容：%2").arg(time, decodedText));

            _decodedText = decodedText;
        }
    }

    void MainWindow::on_checkButton_clicked()
    {
        QString decodedText = _decodedText;

        if (decodedText.isEmpty())
        {
            QMessageBox::warning(this, "提示", "请先扫描二维码");
            return;
        }

        QJsonParseError parseError;
        QJsonDocument doc = QJsonDocument::fromJson(decodedText.toUtf8(), &parseError);

        if (doc.isNull() || !doc.isObject())
        {
            QMessageBox::critical(this, "错误",
                QString("JSON 解析失败：%1\n内容：%2")
                .arg(parseError.errorString())
                .arg(decodedText));
            return;
        }

        QJsonObject jsonObj = doc.object();

        MaterialStock material;
        try {
            material = MaterialStock::fromJson(jsonObj);
        }
        catch (...) {
            QMessageBox::critical(this, "错误", "JSON 格式不匹配，无法转换为 MaterialStock");
            return;
        }

        if (material.getMaterialId().isEmpty() || material.getMaterialName().isEmpty())
        {
            QMessageBox::warning(this, "数据不完整", "物料 ID 或名称不能为空");
            return;
        }

        SqlHelper db;
        QString operatorName = SettingsManager::instance().operatorName();

        bool success = false;
        QString msg;

        int quantity = QInputDialog::getText(
            this, "输入", "请输入 入库/出库 数量：", QLineEdit::Normal, "1", &success).toInt();
        if (!success)
            return;

        if (db.materialExists(material.getMaterialId()))
        {
            if (quantity > 0)
                success = db.stockIn(material.getMaterialId(), quantity, operatorName);
            else if (quantity < 0)
                success = db.stockOut(material.getMaterialId(), quantity, operatorName);

            if (success)
            {
                msg = QString("入库成功！\n物料：%1 (%2)\n入库数量：%3\n当前库存：%4")
                    .arg(material.getMaterialName())
                    .arg(material.getMaterialId())
                    .arg(quantity)
                    .arg(db.getMaterialById(material.getMaterialId()).getStockQuantity());
            }
        }
        else
        {
            if (quantity < 0)
                return;

            QString location = QInputDialog::getText(
                this, "输入", "请输入 货架位置：", QLineEdit::Normal, "Shelves-001", &success);
            if (!success)
                return;
			material.setLocation(location);

            if (!db.addMaterial(material))
            {
                QMessageBox::critical(this, "数据库错误", QString("新增物料失败：%1").arg(db.getLastError()));
                return;
            }

            success = db.stockIn(material.getMaterialId(), quantity, operatorName);

            msg = QString("新物料已添加%1\n物料：%2 (%3)")
                .arg(quantity)
                .arg(material.getMaterialName())
                .arg(material.getMaterialId());
        }

        if (success) {
            QMessageBox::information(this, "成功", msg);

            ui->resultLabel->clear();
            ui->resultTextEdit->clear();
        }
        else {
            QMessageBox::critical(this, "失败", QString("操作失败：%1").arg(db.getLastError()));
        }
    }

    void MainWindow::refreshStockTable()
    {
        ui->stockTable->clearContents();

        SqlHelper db;
        QList<MaterialStock> list = db.getAllMaterials();

        ui->stockTable->setRowCount(list.size());

        for (int row = 0; row < list.size(); ++row)
        {
            const auto& m = list.at(row);

            QTableWidgetItem* itemId = new QTableWidgetItem(m.getMaterialId());
            QTableWidgetItem* itemName = new QTableWidgetItem(m.getMaterialName());
            QTableWidgetItem* itemQty = new QTableWidgetItem(QString::number(m.getStockQuantity()));
            QTableWidgetItem* itemLoc = new QTableWidgetItem(m.getLocation());
            QTableWidgetItem* itemTime = new QTableWidgetItem(m.getCreateTime().toString("yyyy-MM-dd hh:mm:ss"));

            itemQty->setTextAlignment(Qt::AlignCenter);

            ui->stockTable->setItem(row, 0, itemId);
            ui->stockTable->setItem(row, 1, itemName);
            ui->stockTable->setItem(row, 2, itemQty);
            ui->stockTable->setItem(row, 3, itemLoc);
            ui->stockTable->setItem(row, 4, itemTime);
        }

        if (list.isEmpty())
        {
            ui->stockTable->setRowCount(1);
            ui->stockTable->setItem(0, 0, new QTableWidgetItem("暂无物料数据"));
            ui->stockTable->item(0, 0)->setTextAlignment(Qt::AlignCenter);
            ui->stockTable->setSpan(0, 0, 1, 5);
        }
    }

    void MainWindow::refreshOperationTable()
    {
        ui->operationTable->clearContents();

        SqlHelper db;
        QList<StockOperation> list = db.getAllOperations();

        ui->operationTable->setRowCount(list.size());

        for (int row = 0; row < list.size(); ++row)
        {
            const auto& op = list.at(row);

            QTableWidgetItem* itemId = new QTableWidgetItem(QString::number(op.getOperationId()));
            QTableWidgetItem* itemMId = new QTableWidgetItem(op.getMaterialId());
            QTableWidgetItem* itemOpt = new QTableWidgetItem(op.getOperationTypeString());
            QTableWidgetItem* itemQty = new QTableWidgetItem(QString::number(op.getQuantity()));
            QTableWidgetItem* itemOpr = new QTableWidgetItem(op.getOperator());
            QTableWidgetItem* itemTime = new QTableWidgetItem(op.getOperationTime().toString("yyyy-MM-dd hh:mm:ss"));

            itemQty->setTextAlignment(Qt::AlignCenter);

            ui->operationTable->setItem(row, 0, itemId);
            ui->operationTable->setItem(row, 1, itemMId);
            ui->operationTable->setItem(row, 2, itemOpt);
            ui->operationTable->setItem(row, 3, itemQty);
            ui->operationTable->setItem(row, 4, itemOpr);
            ui->operationTable->setItem(row, 5, itemTime);
        }

        if (list.isEmpty())
        {
            ui->operationTable->setRowCount(1);
            ui->operationTable->setItem(0, 0, new QTableWidgetItem("暂无操作数据"));
            ui->operationTable->item(0, 0)->setTextAlignment(Qt::AlignCenter);
            ui->operationTable->setSpan(0, 0, 1, 6);
        }
    }

    void MainWindow::updateStockBarChart()
    {
        SqlHelper db;
        QList<MaterialStock> list = db.getAllMaterials();

        if (list.isEmpty()) {
            qDebug() << "No material data available";
            return;
        }

        QBarSeries* series = new QBarSeries();

        for (const MaterialStock& material : list) {
            QBarSet* set = new QBarSet(material.getMaterialName());
            *set << material.getStockQuantity();
            series->append(set);
        }

        QChart* chart = new QChart();
        chart->addSeries(series);
        chart->setTitle("物料库存统计");
        chart->setAnimationOptions(QChart::SeriesAnimations);

        QStringList categories;
        for (const MaterialStock& material : list) {
            categories << material.getMaterialName();
        }

        QBarCategoryAxis* axisX = new QBarCategoryAxis();
        axisX->append(categories);
        axisX->setTitleText("物料名称");
        chart->addAxis(axisX, Qt::AlignBottom);
        series->attachAxis(axisX);

        QValueAxis* axisY = new QValueAxis();
        axisY->setTitleText("库存数量");
        axisY->setLabelFormat("%d");
        axisY->setMin(0);

        int maxQuantity = 0;
        for (const MaterialStock& material : list) {
            if (material.getStockQuantity() > maxQuantity) {
                maxQuantity = material.getStockQuantity();
            }
        }
        axisY->setMax(maxQuantity * 1.1);

        chart->addAxis(axisY, Qt::AlignLeft);
        series->attachAxis(axisY);

        chart->legend()->setVisible(true);
        chart->legend()->setAlignment(Qt::AlignBottom);

        QChart* oldChart = ui->stockChart->chart();
        if (oldChart) {
            delete oldChart;
        }

        ui->stockChart->setChart(chart);
        ui->stockChart->setRenderHint(QPainter::Antialiasing);
    }

    void MainWindow::on_generateExcelButton_clicked()
    {
        using namespace QXlsx;

        QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
        QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss");

        // 1. 生成【库存总表】
        QString stockFile = desktopPath + QString("/库存报表_%1.xlsx").arg(timeStr);
        Document xlsxStock;

        // 标题样式
        Format titleFmt;
        titleFmt.setFontSize(16);
        titleFmt.setFontBold(true);
        titleFmt.setHorizontalAlignment(Format::AlignHCenter);
        xlsxStock.write("A1", "物料库存总表", titleFmt);
        xlsxStock.mergeCells("A1:E1", titleFmt);

        // 表头
        Format headerFmt;
        headerFmt.setFontBold(true);
        headerFmt.setPatternBackgroundColor(QColor(180, 200, 255));
        QStringList headers = { "物料编号", "物料名称", "库存数量", "库位", "创建时间" };
        for (int i = 0; i < headers.size(); ++i)
            xlsxStock.write(2, i + 1, headers[i], headerFmt);

        // 数据
        SqlHelper db;
        auto materials = db.getAllMaterials();
        int row = 3;
        qint64 totalStock = 0;
        for (const auto& m : materials) 
        {
            xlsxStock.write(row, 1, m.getMaterialId());
            xlsxStock.write(row, 2, m.getMaterialName());
            xlsxStock.write(row, 3, m.getStockQuantity());
            xlsxStock.write(row, 4, m.getLocation());
            xlsxStock.write(row, 5, m.getCreateTime().toString("yyyy-MM-dd hh:mm"));
            totalStock += m.getStockQuantity();
            row++;
        }

        // 汇总行
        Format sumFmt;
        sumFmt.setFontBold(true);
        sumFmt.setPatternBackgroundColor(QColor(255, 255, 200));
        xlsxStock.write(row, 1, "合计", sumFmt);
        xlsxStock.write(row, 2, "总库存数量", sumFmt);
        xlsxStock.write(row, 3, totalStock, sumFmt);
        xlsxStock.mergeCells(CellRange(row, 1, row, 2), sumFmt);

        // 自动列宽
        for (int i = 1; i <= 5; ++i)
            xlsxStock.setColumnWidth(i, 18);

        if (!xlsxStock.saveAs(stockFile)) {
            QMessageBox::critical(this, "错误", "库存报表生成失败！");
            return;
        }

        // 2. 生成【操作明细表】
        QString opFile = desktopPath + QString("/操作记录报表_%1.xlsx").arg(timeStr);
        Document xlsxOp;

        xlsxOp.write("A1", "库存操作明细记录", titleFmt);
        xlsxOp.mergeCells("A1:G1", titleFmt);

        QStringList opHeaders = { "操作ID", "物料编号", "物料名称", "操作类型", "数量", "操作人", "操作时间" };
        for (int i = 0; i < opHeaders.size(); ++i)
            xlsxOp.write(2, i + 1, opHeaders[i], headerFmt);

        auto operations = db.getAllOperations();
        row = 3;
        int inTotal = 0, outTotal = 0;
        for (const auto& op : operations) {
            MaterialStock mat = db.getMaterialById(op.getMaterialId());
            xlsxOp.write(row, 1, op.getOperationId());
            xlsxOp.write(row, 2, op.getMaterialId());
            xlsxOp.write(row, 3, mat.getMaterialName());
            QString typeStr = op.getOperationType() == StockOperation::In ? "入库" : "出库";
            xlsxOp.write(row, 4, typeStr);
            xlsxOp.write(row, 5, op.getQuantity());
            xlsxOp.write(row, 6, op.getOperator());
            xlsxOp.write(row, 7, op.getOperationTime().toString("yyyy-MM-dd hh:mm:ss"));

            if (op.getOperationType() == StockOperation::In) inTotal += op.getQuantity();
            else outTotal += op.getQuantity();
            row++;
        }

        // 汇总
        xlsxOp.write(row, 1, "汇总", sumFmt);
        xlsxOp.write(row, 2, "总入库", sumFmt);
        xlsxOp.write(row, 3, inTotal, sumFmt);
        xlsxOp.write(row + 1, 2, "总出库", sumFmt);
        xlsxOp.write(row + 1, 3, outTotal, sumFmt);
        xlsxOp.mergeCells(CellRange(row, 1, row + 1, 1), sumFmt);

        for (int i = 1; i <= 7; ++i)
            xlsxOp.setColumnWidth(i, 20);

        if (!xlsxOp.saveAs(opFile)) {
            QMessageBox::critical(this, "错误", "操作报表生成失败！");
            return;
        }

        // 成功提示
        QMessageBox::information(this, "成功！",
            QString("报表已生成到桌面：\n\n%1\n%2\n\n点击可直接打开查看")
            .arg(QDir::toNativeSeparators(stockFile))
            .arg(QDir::toNativeSeparators(opFile)));

        // 可选：自动打开文件夹
        QDesktopServices::openUrl(QUrl::fromLocalFile(desktopPath));
    }

    QImage MainWindow::cvMatToQImage(const cv::Mat& mat)
    {
        if (mat.type() == CV_8UC4) {
            return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        }
        else if (mat.type() == CV_8UC3) {
            QImage qimg(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
            return qimg.rgbSwapped();
        }
        else if (mat.type() == CV_8UC1) {
            return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        }
        else {
            return QImage();
        }
    }

}
